package com.apes.enquiry.product.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.enquiry.brand.repository.SpBrandRepository;
import com.apes.enquiry.product.model.AccumulatorProduct;
import com.apes.enquiry.product.model.SpProduct;
import com.apes.enquiry.product.repository.AccumulatorProductRepository;
import com.apes.enquiry.product.repository.SpProductRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.LogicalUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import com.apestech.framework.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @className: com.apes.enquiry.product.service.AccumulatorProductService
 * @description: 描述
 * @author: wsl
 * @create: 2022-11-07 17:44
 */
@Service
public class AccumulatorProductService extends DomainService {
    @Autowired
    private SpBrandRepository spBrandRepository;

    @Autowired
    private AccumulatorProductRepository accumulatorProductRepository;

    @Autowired
    private SpProductRepository spProductRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 上传蓄电池商品入口
     *
     * @param request
     */
    public void uploadingAccumulatorProduct(SimpleRequest request) {
        //Excel信息
        JSONObject importData = request.get("importData");
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        //准入校验与数据补全
        List accumulatorProducts = appendImportReturn_New(importData, user);
        if (accumulatorProducts.size() <= 0) return;
        List accumulatorProduct = Collections.synchronizedList(new ArrayList());
        for(int i=0;i<accumulatorProducts.size();i++){
            accumulatorProduct.add(accumulatorProducts.get(i));
            if((i!=0 && i%1000==0) || i==accumulatorProducts.size()-1){
                SimpleDateFormat sdf = new SimpleDateFormat("yy-mm-dd HH:mm:ss");
                //通过事务发件箱实现标准对照/状态字段回写
                OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
                wrapper.setSubscriber("sp.accumulatorProduct.standardContrast");
                String random = String.valueOf(Math.random()).substring(0,3);
                //聚合根ID（非必项）tp:方便追溯发生异常的服务,(当前用户账号加时间戳)
                wrapper.setAggregateId(user.getOrigin() + sdf.format(new Date())+random);
                wrapper.setPayload(JSON.toJSONString(accumulatorProduct));
                SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
                accumulatorProduct=Collections.synchronizedList(new ArrayList());
            }
        }

    }

    /**
     * 准入校验与数据补全
     *
     * @param importData
     * @param user
     * @return
     */
    private List appendImportReturn_New(JSONObject importData, User user) {
        List accumulatorProducts = Collections.synchronizedList(new ArrayList());
        List notProducts = Collections.synchronizedList(new ArrayList());
        //（零件号+品牌）列表
        Set<String> PNAndBrand = spProductRepository.findPNAndBrandAll();
        //所有品牌
        List<String> allName = spBrandRepository.findAllName();
        //开始校验数据
        importData.forEach((k, v) -> {
            JSONArray importArray = (JSONArray) v;
            if(((JSONArray) importArray.get(0)).size()!=19) throw new RuntimeException("导入模板错误，请检查文件并重新上传！");
            if (importArray.size() > 10000) throw new RuntimeException("系统单次导入最大可以接受1W条数据，请检查文件大小并重新上传！");
            AtomicInteger i = new AtomicInteger(1);
            double size = importArray.size();
            importArray.parallelStream().forEach(item -> {
                JSONArray iValueArray = (JSONArray) item;
                //进度条
                i.getAndIncrement();
                double percent = (i.get() / size) * 100;
                int progress = (int) percent;
                stringRedisTemplate.opsForValue().set("Accumulator" + user.getOrigin(), "" + progress, 2, TimeUnit.MINUTES);

                //跳过列名和导入规则行
                if (iValueArray.size() < 3 || "零件号".equals(iValueArray.getString(0))) return;

                String pn = "";
                String brand = "";
                String name = "";
                String merchantProduct = "";
                String international = "";
                String reference = "";
                String type = "";
                String series = "";
                String capacity = "";
                String voltage = "";
                String sizes = "";
                String terminal = "";
                String electricity = "";
                String placeOfOrigin = "";
                String guaranteePeriod = "";

                for (int j = 0; j < iValueArray.size(); j++) {
                    if (Objects.isNull(iValueArray.get(j))) continue;
                    switch (j) {
                        case 0: pn = iValueArray.getString(0);
                            break;
                        case 1: brand = iValueArray.getString(1);
                            break;
                        case 2: name = iValueArray.getString(2);
                            break;
                        case 3: merchantProduct = iValueArray.getString(3);
                            break;
                        case 4: international = iValueArray.getString(4);
                            break;
                        case 5: reference = iValueArray.getString(5);
                            break;
                        case 6: type = iValueArray.getString(6);
                            break;
                        case 7: series = iValueArray.getString(7);
                            break;
                        case 8: capacity = iValueArray.getString(8);
                            break;
                        case 9: voltage = iValueArray.getString(9);
                            break;
                        case 10: sizes = iValueArray.getString(10);
                            break;
                        case 11: terminal = iValueArray.getString(11);
                            break;
                        case 12: electricity = iValueArray.getString(12);
                            break;
                        case 17: placeOfOrigin = iValueArray.getString(17);
                            break;
                        case 18: guaranteePeriod = iValueArray.getString(18);
                            break;
                    }
                }
                if(guaranteePeriod==null||guaranteePeriod.equals("")){
                    guaranteePeriod="0";
                }
                //0、零件号 1、品牌 2、商品名称 3、商家编码 4、国际标号 5、参考号 6、类型 7、系列 8、额定容量 9、额定电压 10、尺寸 11、端子 12、冷启动电流 13、产品描述 14、库存数量 15、不含税单价 16、上架状态、产地
                String[] strings = {brand, sizes, terminal};
                if ( UploadingProductUtil.isAllNotEmpty(pn, brand,international, reference, type, series,capacity, voltage, sizes, terminal)&&(guaranteePeriod.equals("0")||guaranteePeriod.equals("1")||
                        guaranteePeriod.equals("3")||guaranteePeriod.equals("6")||guaranteePeriod.equals("12")||guaranteePeriod.equals("24"))
                     && this.formatCheck(strings, allName) && this.digitCheck(capacity, voltage, electricity) &&
                        LogicalUtil.in(iValueArray.getString(6),"免维护蓄电池","AGM启停蓄电池","EFB启停蓄电池") &&
                        PNAndBrand.add(iValueArray.getString(0) + iValueArray.getString(1) + user.getPerson().getId())) {

                    //数据初始化与数据补全
                    SpProduct spProduct = new SpProduct();
                    spProduct.setName(name);
                    spProduct.setSupplier(user.getPerson());
                    spProduct.setType("蓄电池");
                    spProduct.setSpBrand(spBrandRepository.findByName(brand));
                    spProduct.setQuality(spProduct.getSpBrand().getQualityName());
                    spProduct.setOE(pn);
                    spProduct.setGuaranteePeriod(guaranteePeriod);
                    spProduct.setMerchantProduct(merchantProduct);
                    //非必填数据
                    maybe(iValueArray, spProduct);
                    spProduct.setPlaceOfOrigin(placeOfOrigin);
                    //主数据数据补全
                    spProduct.setMateState("underway");
                    spProduct.setProductState("review");
                    spProduct.setStandardType("Accumulator");

                    //蓄电池数据补全
                    AccumulatorProduct accumulatorProduct = new AccumulatorProduct();
                    accumulatorProduct.setSpProduct(spProductRepository.saveAndFlush(spProduct));
                    accumulatorProduct.setInternational(international);
                    accumulatorProduct.setReference(reference);
                    accumulatorProduct.setType(type);
                    accumulatorProduct.setSeries(series);
                    accumulatorProduct.setCapacity(Double.valueOf(capacity));
                    accumulatorProduct.setVoltage(Double.valueOf(voltage));
                    accumulatorProduct.setSizes(sizes);
                    accumulatorProduct.setTerminal(terminal);
                    accumulatorProduct.setElectricity("".equals(electricity)?0.00:Double.valueOf(electricity));

                    //保存
                    accumulatorProducts.add(accumulatorProductRepository.save(accumulatorProduct));
                } else {
                    notProducts.add(UploadingProductUtil.accumulatorCause(iValueArray, allName, PNAndBrand, user.getPerson().getId()));
                }

            });
        });
        accumulatorProductRepository.flush();
        //用Redis，缓存进度条和结果
        stringRedisTemplate.opsForValue().set("not_accumulatorProducts" + user.getOrigin(), notProducts.toString(), 2, TimeUnit.HOURS);
        //进度条100%
        stringRedisTemplate.opsForValue().set("Accumulator" + user.getOrigin(), "100", 2, TimeUnit.MINUTES);
        //用于结果页面展示
        stringRedisTemplate.opsForValue().set("successfulAccumulator" + user.getOrigin(), "" + accumulatorProducts.size(), 4, TimeUnit.MINUTES);
        stringRedisTemplate.opsForValue().set("failingAccumulator" + user.getOrigin(), "" + notProducts.size(), 4, TimeUnit.MINUTES);
        return accumulatorProducts;
    }

    /**
     * 非必填数据，防止下标越界
     *
     * @param iValueArray
     * @param spProduct
     */
    private void maybe(JSONArray iValueArray, SpProduct spProduct) {
        spProduct.setNotTaxUnitPrice(0.00);
        spProduct.setMerchantStockQty(0);
        spProduct.setPutawayState(false);
        switch (iValueArray.size()){
            case 14:{
                spProduct.setDescribe(iValueArray.getString(13));
                break;
            }
            case 15:{
                spProduct.setDescribe(iValueArray.getString(13));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(14)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(14)) ? iValueArray.getInteger(14) : 0);
                break;
            }
            case 16:{
                spProduct.setDescribe(iValueArray.getString(13));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(14)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(14)) ? iValueArray.getInteger(14) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(15)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(15)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(15))) : 0L);
                break;
            }
            case 17:{
                spProduct.setDescribe(iValueArray.getString(13));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(14)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(14)) ? iValueArray.getInteger(14) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(15)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(15)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(15))) : 0L);
                spProduct.setPutawayState("上架".equals(iValueArray.getString(16)));
                break;
            }
            case 18:{
                spProduct.setDescribe(iValueArray.getString(13));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(14)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(14)) ? iValueArray.getInteger(14) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(15)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(15)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(15))) : 0L);
                spProduct.setPutawayState("上架".equals(iValueArray.getString(16)));
                break;
            }
            case 19:{
                spProduct.setDescribe(iValueArray.getString(13));
                spProduct.setMerchantStockQty(Objects.isNull(iValueArray.getString(14)) ? 0 :
                        Pattern.matches("[0-9]*", iValueArray.getString(14)) ? iValueArray.getInteger(14) : 0);
                spProduct.setNotTaxUnitPrice(Objects.isNull(iValueArray.getString(15)) ? 0 :
                        Pattern.matches("^\\d+(\\.\\d+)?$", iValueArray.getString(15)) ?
                                Double.parseDouble(String.format("%.2f", iValueArray.getDouble(15))) : 0L);
                spProduct.setPutawayState("上架".equals(iValueArray.getString(16)));
                break;
            }
        }
    }


    /**
     * 标准对照与字段回写
     *
     * @param outboxPayloadWrapper
     */
    @OutboxSubscriber(id = "sp.accumulatorProduct.standardContrast", name = "通过事务发件箱实现标准对照/状态字段回写")
    public void standardContrast(OutboxPayloadWrapper outboxPayloadWrapper) {
        //导入商品数据
        JSONArray importData = JSON.parseArray(outboxPayloadWrapper.getPayload());

        if (importData.size() <= 0) return;
        //数据中心标准数据
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("key", "value");
        JSONObject json = JSON.parseObject(super.invoke("cm.accumulatorProduct.findAllByStandard", jsonObject));
        JSONArray body = json.getJSONArray("body");
        Set<String> set = new HashSet<>();
        //数据对比与状态回写，将品牌+国际标号+参考号做为map的key
        Map<String, JSONObject> conditionMap = body.parallelStream().filter(data -> {
            JSONObject accumulator = (JSONObject)data;
            String upperCase = (accumulator.getString("brand") + accumulator.getString("grade") + accumulator.getString("reference")).toUpperCase();
            return Objects.nonNull(data) && set.add(upperCase);
        }).collect(Collectors.toMap(item -> {
                    JSONObject accumulatorProduct = (JSONObject) item;
                    return (accumulatorProduct.getString("brand") + accumulatorProduct.getString("grade") + accumulatorProduct.getString("reference")).toUpperCase();
                },
                item -> {
                    JSONObject accumulatorProduct = (JSONObject) item;
                    return accumulatorProduct;
                }));

        //匹配
        importData.stream().forEach(item -> {
            String id = ((JSONObject) item).getString("id");
            AccumulatorProduct accumulatorProduct = null;
            if(StringUtil.isEmpty(((JSONObject) item).getString("oE"))){
                accumulatorProduct = accumulatorProductRepository.findOne(id);
            }else{
                accumulatorProduct  = accumulatorProductRepository.findBySpId(id);
            }
            if(accumulatorProduct!=null){
                JSONObject normalData = conditionMap.get((accumulatorProduct.getSpProduct().getSpBrand().getName()
                        + accumulatorProduct.getInternational() + accumulatorProduct.getReference()).toUpperCase());

                if (Objects.nonNull(normalData)) {
                    //匹配成功
                    SpProduct spProduct = accumulatorProduct.getSpProduct();
                    spProduct.setMateState("succeed");
                    spProduct.setProductState(spProduct.isPutawayState() ? "offer" : "awaitPutaway");
                    spProduct.setStandardId(normalData.getString("id"));
                    spProductRepository.saveAndFlush(spProduct);
                } else {
                    //匹配失败
                    SpProduct spProduct = accumulatorProduct.getSpProduct();
                    spProduct.setMateState("fail");
                    spProduct.setProductState("notOffer");
                    spProductRepository.saveAndFlush(spProduct);
                }
            }
        });
    }

    /**
     * String格式校验
     *
     * @param strings
     * @return
     */
    public boolean formatCheck(String[] strings, List<String> allName) {
        if (strings.length == 0) {
            return false;
        }

        for (String item : strings) {
            if (allName.contains(item) || "正装，反装".contains(item)) {
                continue;
            }
            if (Pattern.matches("^(\\d+)\\*(\\d+)\\*(\\d+)$", item)) {
                continue;
            }
            return false;
        }
        return true;
    }

    /**
     * 校验数字
     *
     * @param strings
     * @return
     */
    public boolean digitCheck(String... strings) {
        if (strings.length == 0) {
            return false;
        }
        for (String item : strings) {
            if(item==null || "".equals(item)) continue;
            if (!Pattern.matches("^\\d+(\\.\\d+)?$", item)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 进度条
     *
     * @return
     */
    public String progress(SimpleRequest request) {
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        String accumulator = stringRedisTemplate.opsForValue().get("Accumulator" + user.getOrigin());
        if ("100".equals(accumulator)) stringRedisTemplate.delete("Accumulator" + user.getOrigin());
        return accumulator;
    }

    /**
     * 上传结果
     *
     * @param request
     * @return
     */
    public String resultPage(SimpleRequest request) {
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        return "本次成功导入" + stringRedisTemplate.opsForValue().get("successfulAccumulator" + user.getOrigin()) + "条\n"
                + "导入失败" + stringRedisTemplate.opsForValue().get("failingAccumulator" + user.getOrigin()) + "条";
    }

    /**
     * 下载失败结果
     *
     * @param request
     * @return
     */
    public Map detail(SimpleRequest request) {
        User user = userRepository.findOne(Integer.parseInt(request.getSession().getUserId()));
        String accumulatorProducts = stringRedisTemplate.opsForValue().get("not_accumulatorProducts" + user.getOrigin());
        JSONArray objects = JSONArray.parseArray(accumulatorProducts);
        assert objects != null;
        stringRedisTemplate.delete("not_accumulatorProducts" + user.getOrigin());
        return MapUtil.mapper("content", new ArrayList<>(objects), "total", objects.size(), "pages", request.get("page"));
    }
}

